#include <string.h>
#include <aos/cli.h>
#include "aos/kernel.h"
#include "time.h"
#include <stdio.h>
#include "linkvisual_client.h"
#include "cx_record.h"
#include "cx_cloud.h"
#include "cx_utility.h"
#include "iot_import.h"
#include "dirent.h"
#include "record.h"

extern void *cxrecord_hdl;

static void rm_dir(void *args)
{
    DIR *dp;
    struct dirent *out_dirent;
    char *destination = (char *)malloc(1024);
    
    char *path = args;
    dp = (DIR *)opendir(path);

    if(!dp){
        unlink(path);
        return;
    }

    while (1) {
        out_dirent = readdir(dp);
        if(!out_dirent){
            break;
        }
        strncpy(destination, path, 1024);
        strcat(destination, "/");
        strcat(destination, out_dirent->d_name);
        // aos_cli_printf("%s\r\n", destination);
        rm_dir(destination);
    }

    closedir(dp);
    rmdir(path);
    free(destination);
}

static void task_entry(void *paras)
{
    int ret;
    char product_key[PRODUCT_KEY_LEN + 1];
    char device_name[DEVICE_NAME_LEN + 1];
    char device_secret[DEVICE_SECRET_LEN + 1];
    char product_secret[PRODUCT_SECRET_LEN + 1];
    int log_level = CX_CLOUD_LOG_WARN;//默认debug日志级别

    if ((0 == HAL_GetProductKey(product_key)) || (0 == HAL_GetProductSecret(product_secret)) ||
        (0 == HAL_GetDeviceSecret(device_secret)) || (0 == HAL_GetDeviceName(device_name))) {
        printf("!!!!!! missing ProductKey/ProductSecret/DeviceName/DeviceSecret\n");
        return;
    }
    cx_cloud_param_t param;
    param.dev_id = 0;
    param.device_name = device_name;
    param.device_secret = device_secret;
    param.product_key = product_key;
    param.product_secret = product_secret;
    param.log_level = log_level;

    void *cxcloud_hdl;
    cxcloud_hdl = cx_cloud_init(&param, NULL);
    cx_cloud_connect(cxcloud_hdl);
    //创建按键检测 用于单向对讲
    extern void intercom_button_check(void *paras);
    aos_task_t button_register_thread;
    ret = aos_task_new_ext(&button_register_thread, "intercom_button_check", intercom_button_check, NULL, 10*1024, 50);
    if (ret != 0) {
		printf("button task create failed\r\n");
    }
    aos_task_exit(0);
}



static void record_save_task_entry(void *paras)
{
    uint32_t time = 15000;
    if(paras) {
        time = atoi((char *)paras);
    }
    
    uint8_t record_save_name[128];
    if(!cxrecord_hdl) {
        printf("cx_record not init\n");
        return;
    }
    cx_vr_record_start(cxrecord_hdl, 0, record_save_name, time);
    aos_task_exit(0);
}

void record_video_save(void *param)
{
    aos_task_new("record_task", record_save_task_entry, param, 16384);
}
static aos_sem_t snap_shot_sem;
static int snap_shot_running_flag;
static unsigned char snap_shot_buff[500*1024];
static void snap_test_task_entry(void *paras)
{
    int ret;
    char image_name[MAX_RECORD_NAME_LEN];
    while(1) {
        aos_sem_wait(&snap_shot_sem, AOS_WAIT_FOREVER);
        snap_shot_running_flag = 1;
        ret = cx_vr_snapshot(cxrecord_hdl, 0, (uint8_t *)image_name);
        if(ret < 0) {
            snap_shot_running_flag = 0;
            continue;
        }
        FILE *fp = fopen(image_name, "r");
        if (!fp) {
            printf("Open file failed: %s\n", image_name);
            snap_shot_running_flag = 0;
            continue;
        }
        fseek(fp, 0, SEEK_END);
        unsigned int file_size = ftell(fp);
        if(file_size > sizeof(snap_shot_buff)) {
            printf("snap_shot pic size too large:%d\n", file_size);
            snap_shot_running_flag = 0;
            continue;
        }
        fseek(fp, 0, SEEK_SET);
        ret = fread(snap_shot_buff, 1, file_size, fp);
        if(ret != file_size) {
            printf("File read error: %s\n", image_name);
            fclose(fp);
            snap_shot_running_flag = 0;
            continue;
        }
        fclose(fp);
        cx_cloud_snapshot_upload(cxrecord_hdl, snap_shot_buff, file_size);
        snap_shot_running_flag = 0;
    }
    aos_task_exit(0);
}

void lv_demo_start(void)
{
    aos_task_new("lv_demo", task_entry, NULL, 8192);
}
int lv_timestamp = 0;
void cmd_lv_test(char *wbuf, int wbuf_len, int argc, char **argv)
{
    int flag = atoi(argv[1]);
    if(flag == 1) {
        lv_timestamp+=50;
    } else {
        lv_timestamp-=50;
    }
    printf("time stamp:%d\n", lv_timestamp);
    // lv_demo_start();
}

void cmd_record_test(char *wbuf, int wbuf_len, int argc, char **argv)
{
    if(strcmp(argv[1], "snap") == 0) {
        if(strcmp(argv[2], "shot") == 0) {
            if(cx_vr_get_record_status(cx_record_get_handle())) {
                printf("record runnning, quit\n");
                return;
            }
            static int snap_shot_first_flag = 0;
            if(snap_shot_first_flag == 0) {
                aos_task_t snap_shot_task;
                aos_sem_new(&snap_shot_sem, 0);
                aos_task_new_ext(&snap_shot_task, "snap_shot", snap_test_task_entry, NULL, 8192, 38);
                snap_shot_first_flag = 1;
            }
            if(snap_shot_running_flag) {
                printf("snap_shot running\n");
                return;
            }
            aos_sem_signal(&snap_shot_sem);
        }
        else if(strcmp(argv[2], "search") == 0) {
            if(argv[3] && argv[4]) {
                uint32_t start_time = atoi(argv[3]);
                uint32_t stop_time = atoi(argv[4]);
                cx_vr_snapshot_info_t images[100];
                cx_vr_snapshot_search(cxrecord_hdl, start_time, stop_time, images, 100);
            }
        } else if(strcmp(argv[2], "get") == 0) {
            uint8_t *image = (uint8_t *)malloc(100*1024);
            cx_vr_snapshot_get(cxrecord_hdl, (uint8_t *)argv[3], image, 0, 100*1024);
            free(image);
        }
    } else if(strcmp(argv[1], "video") == 0) {
        if(strcmp(argv[2], "start") == 0) {
            record_video_save(argv[3]);
        } else if(strcmp(argv[2], "stop") == 0) {
            cx_vr_record_stop(cxrecord_hdl);
        }
        else if(strcmp(argv[2], "search") == 0) {
            if(argv[3] && argv[4]) {
                uint32_t start_time = atoi(argv[3]);
                uint32_t stop_time = atoi(argv[4]);
                cx_vr_video_info_t info[100];
                cx_vr_video_search(cxrecord_hdl, start_time, stop_time, info, 100);
            }
        }
    } else if(strcmp(argv[1], "get_time") == 0) {
        time_t utime;
        struct tm *tm = NULL;
        long long start_time, stop_time;

        time(&utime);
        tm = localtime(&utime);
        if (tm) {
            cx_util_utc_to_beijing(tm);
        }
        start_time = utime - (tm->tm_hour*3600+tm->tm_min*60+tm->tm_sec);
        stop_time = start_time + 24*60*60 - 1; 
        printf("current day start time:%lld, stop time:%lld\n", start_time, stop_time);
    }
}

void cmd_rmdir_test(char *wbuf, int wbuf_len, int argc, char **argv) 
{
    aos_task_new("rmdir_task", rm_dir, argv[1], 4096);
}

static void parse_record_index_file(void *args)
{   
    cx_record_index_head index_head;
    cx_record_index_segment_head segment_head;
    cx_record_index_frame index_frame;
    char **argv = (char **)args;
    int seg_index_len;
    int opcode = 2;
    uint32_t time_stamp = 0, time_stamp_last = 0, video_timestamp = 0, video_timestamp_last = 0, audio_timestamp = 0, audio_timestamp_last = 0;
    uint16_t calc_crc = 0, raw_crc = 0;
    FILE *fp = fopen(argv[1], "r");
    if(!fp) {
        printf("open file:%s fail\n", argv[1]);
        return;
    }
    if(argv[2]) {
        opcode = atoi(argv[2]);
    }
    fread(&index_head, 1, sizeof(index_head), fp);
    printf("record info:\n");
    printf("start time:%llds duration:%dms file_size:%d segment:%d\n", index_head.start_time, index_head.duration, index_head.file_size, index_head.segment_num);
    printf("video type:%d fps:%d\n", index_head.video_param.video_type, index_head.video_param.fps);
    printf("audio type:%d channel:%d sample_rate:%d sample_bits:%d\n", index_head.audio_param.audio_type, index_head.audio_param.channel, index_head.audio_param.sample_rate, index_head.audio_param.sample_bits);
    for(int i=0;i<index_head.segment_num;i++) {
        fread(&segment_head, 1, sizeof(segment_head), fp);
        printf("segment:%d start time:%lld duration:%d pos:%d\n", i, segment_head.start_time, segment_head.duration, segment_head.next_segment_pos);
        seg_index_len = segment_head.next_segment_pos - ftell(fp);
        calc_crc = 0;
        for(int i=0; i< seg_index_len/sizeof(cx_record_index_frame); i++) {
            fread(&index_frame, 1, sizeof(index_frame), fp);
            calc_crc = cx_util_crc16(calc_crc, (unsigned char *)&index_frame, sizeof(index_frame));
            if((opcode == 2) || (opcode == index_frame.media_type)){
                printf("index=%5d media=%d,offset=%8x,len=%5d,timestamp=%8d,key=%d\n", i, index_frame.media_type, index_frame.offset, index_frame.len, index_frame.time_stamp, index_frame.key_frame_flag);
            }
            time_stamp = index_frame.time_stamp;
            if(index_frame.media_type) {
                audio_timestamp = index_frame.time_stamp;
                if((audio_timestamp - audio_timestamp_last) > 60) {
                    printf("audio interval:%d\n", audio_timestamp - audio_timestamp_last);
                }
                audio_timestamp_last = audio_timestamp;
            } else {
                video_timestamp = index_frame.time_stamp;
                if((video_timestamp - video_timestamp_last) > 60) {
                    printf("video interval:%d\n", video_timestamp - video_timestamp_last);
                }
                video_timestamp_last = video_timestamp;
            }
            
            if((time_stamp > time_stamp_last) && ((time_stamp - time_stamp_last) > 60)) {
                printf("frame interval:%d\n", time_stamp - time_stamp_last);
            } else if(time_stamp < time_stamp_last) {
                printf("!!! frame error\n");
            }
            time_stamp_last = time_stamp;
        }
        fread(&raw_crc, 1, sizeof(raw_crc), fp);
        printf("seg info crc_calc:0x%x crc_raw:0x%x\n", calc_crc, raw_crc);
        fseek(fp, segment_head.next_segment_pos, SEEK_SET);
    }
    fclose(fp);
}

void cmd_parse_index(char *wbuf, int wbuf_len, int argc, char **argv) 
{
    aos_task_new("parse_index_task", parse_record_index_file, argv, 4096);
}

static int move_offset = 0;
static unsigned int file_size;
static char *file_buf;
static void read_file_func(void *args)
{
	int move_step = 1024;
	int move_block = 1;
	uint64_t read_bit;
    FILE *fp = fopen(args, "r");
    if(!fp) {
        printf("open file err\n");
        return;
    }
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    file_buf = (char *)malloc(file_size);
    if(!file_buf) {
        printf("malloc fail\n");
        fclose(fp);
        return;
    }
    while(!feof(fp)) {
        read_bit = fread(file_buf + move_offset, move_block, move_step, fp);
		move_offset+=read_bit*move_block;
    }
	fclose(fp);
    free(file_buf);
    printf("read file success\n");
}

void cmd_read_file(char *wbuf, int wbuf_len, int argc, char **argv) 
{
    aos_task_new("parse_index_task", read_file_func, argv[1], 4096);
}

void cmd_fread(char *wbuf, int wbuf_len, int argc, char **argv) 
{
    int off = 0;
    int offset = atoi(argv[2]);
    int file_size;
    int opcode = atoi(argv[3]);
    if(opcode) {
        long long time_enter = aos_now_ms();
        char file_name[128];
        FILE *fp = fopen(argv[1], "r");
        if(!fp)
            return;
        fseek(fp, 0, SEEK_END);
        file_size = ftell(fp);
        char *buff = (char *)malloc(file_size);
        if(!buff) {
            printf("cmd_fread malloc fail\n");
            fclose(fp);
            return;
        }
        fseek(fp, 0, SEEK_SET);
        // fseek(fp, offset, SEEK_SET);
        while(!feof(fp)) {
            ftell(fp);
            int ret = fread(buff + off, 1, 1379, fp);
            off += ret;
            // aos_msleep(1);
        }
        fclose(fp);
        long long time_exit = aos_now_ms();
        printf("read over %d %lld\n", off, time_exit - time_enter);
        snprintf(file_name, 128, "%s_%d", argv[1], offset);
        long long time_enter2 = aos_now_ms();
        FILE *fp_w = fopen(file_name, "w");
        if(!fp_w) {
            printf("open error\n");
            return;
        }
        for(int i = 0;i< file_size;i+=1024) {
            fwrite(buff+i, 1, 1024, fp_w);
        }
        fclose(fp_w);
        long long time_exit2 = aos_now_ms();
        printf("write over %lld\n", time_exit2 - time_enter2);
        free(buff);
    } else {
        long long time_enter = aos_now_ms();
        char file_name[128];
        int fp = aos_open(argv[1], O_RDONLY);
        if(fp < 0)
            return;
        aos_lseek(fp, 0, SEEK_END);
        file_size = aos_tell(fp);
        char *buff = (char *)malloc(file_size);
        if(!buff) {
            printf("cmd_fread malloc fail\n");
            aos_close(fp);
            return;
        }
        aos_lseek(fp, 0, SEEK_SET);
        while(off<file_size) {
            int ret = aos_read(fp, buff + off, 1024);
            off += ret;
        }
        aos_close(fp);
        long long time_exit = aos_now_ms();
        printf("read over %d %lld\n", off, time_exit - time_enter);
        snprintf(file_name, 128, "%s_%d", argv[1], offset);
        long long time_enter2 = aos_now_ms();
        int fp_w = aos_open(file_name, O_RDWR | O_CREAT | O_TRUNC);
        if(fp_w<0) {
            printf("open error\n");
            return;
        }
        for(int i = 0;i< file_size;i+=1024) {
            aos_write(fp_w, buff+i, 1024);
        }
        aos_close(fp_w);
        long long time_exit2 = aos_now_ms();
        printf("write over %lld %d\n", time_exit2 - time_enter2, file_size);
        free(buff);
    }
}

void cli_reg_cmd_lv(void)
{
    static const struct cli_command cli_info_adb_start = {"lv", "lv test", cmd_lv_test};
    aos_cli_register_command(&cli_info_adb_start);

    static const struct cli_command cli_info_record_test = {"record", "record test", cmd_record_test};
    aos_cli_register_command(&cli_info_record_test);

    static const struct cli_command cli_info_rmdir_start = {"rmdirf", "rmdir", cmd_rmdir_test};
    aos_cli_register_command(&cli_info_rmdir_start);

    static const struct cli_command cli_info_parseidnex_start = {"parseindex", "parseindex", cmd_parse_index};
    aos_cli_register_command(&cli_info_parseidnex_start);

    static const struct cli_command cli_info_readfile_start = {"readfile", "readfile", cmd_read_file};
    aos_cli_register_command(&cli_info_readfile_start);

    static const struct cli_command cli_info_fread = {"fread", "readfile", cmd_fread};
    aos_cli_register_command(&cli_info_fread);
}

/*
    record video start/stop                     录像开始(默认15s)/停止
    record video search start_time stop_time    录像查找
    record snap shot                            触发一次抓拍并上云
    record snap search start_time stop_time     抓拍 照片查找
*/